﻿using System;
using System.Collections;

namespace Codemonk.Updater.Server
{
    internal class Scheduler
    {
        public Scheduler(int count = 16)
        {
            items = new WorkItem[count];
            for (int i = 0; i < count; i++)
            {
                items[i] = new WorkItem();
            }
        }

        private int index = 0;

        private WorkItem[] items = null;

        private readonly object _sync = new object();

        private Hashtable table = Hashtable.Synchronized(new Hashtable());

        public void AddClient(IClient client)
        {
            if (client == null) return;
            lock (_sync)
            {
                if (client == null) return;
                table.Add(client, client);
                WorkItem item = null;
                while (item == null)
                {
                    index = System.Threading.Interlocked.Increment(ref index);
                    if (index >= items.Length) index = 0;
                    item = items[index];
                }
                item.Add(client);
            }
        }

        private sealed class WorkItem
        {
            private volatile int counter = 0;
            private volatile bool isStarted = false;

            public bool IsStarted
            {
                get { return isStarted; }
            }
            private volatile bool isStoped = false;
            private int maxEmptyCount = 1000;

            public void Add(IClient client)
            {
                if (isStoped) return;
                bag.Enqueue(client);
                if (!isStarted)
                {
                    lock (this)
                    {
                        if (!isStarted)
                        {
                            isStarted = true;
                            System.Threading.ThreadPool.QueueUserWorkItem(state => Run());
                        }
                    }
                }
            }

            private void Run()
            {
                while (isStarted)
                {
                    try
                    {
                        IClient client = bag.Dequeue() as IClient;
                        if (client != null)
                        {
                            counter = 0;
                            try
                            {
                                client.Stream = FileReader.ReadFile(client.AppID, client.FileName);
                            }
                            catch
                            {
                                client.Stream = null;
                            }
                        }
                        else
                        {
                            counter++;
                            if (counter > maxEmptyCount)
                                isStarted = false;
                        }
                    }
                    catch
                    {
                        counter++;
                        if (counter > maxEmptyCount)
                            isStarted = false;
                    }
                    System.Threading.Thread.Sleep(0);
                }
            }

            public void Stop()
            {
                isStoped = true;
                isStarted = false;
            }

            private Queue bag = Queue.Synchronized(new Queue());
        }
    }
}
